/*
 * Copyright 2025 LinQingYing. and contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of this source code is governed by the Apache License 2.0,
 * which allows users to freely use, modify, and distribute the code,
 * provided they adhere to the terms of the license.
 *
 * The software is provided "as-is", and the authors are not responsible for
 * any damages or issues arising from its use.
 *
 */



package org.cangnova.cangjie.ide.formatter

import org.cangnova.cangjie.lang.CangJieLanguage
import org.cangnova.cangjie.messages.CangJieBundle
import com.intellij.application.options.CodeStyleAbstractPanel
import com.intellij.openapi.application.ApplicationBundle
import com.intellij.openapi.editor.colors.EditorColorsScheme
import com.intellij.openapi.util.NlsContexts
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.ui.JBIntSpinner
import com.intellij.ui.components.JBScrollPane
import com.intellij.ui.dsl.builder.*
import com.intellij.ui.layout.selected
import com.intellij.util.ui.JBUI

import javax.swing.JCheckBox
import javax.swing.JRadioButton
import javax.swing.table.AbstractTableModel

class ImportSettingsPanelWrapper(settings: CodeStyleSettings) :
    CodeStyleAbstractPanel(CangJieLanguage, null, settings) {

    private val importsPanel = ImportSettingsPanel()
    private val content = JBScrollPane(importsPanel.panel)

    override fun getRightMargin() = throw UnsupportedOperationException()

    override fun createHighlighter(scheme: EditorColorsScheme) = throw UnsupportedOperationException()

    override fun getFileType() = throw UnsupportedOperationException()

    override fun getPreviewText(): String? = null

    override fun apply(settings: CodeStyleSettings) = importsPanel.apply(settings.cangjieCustomSettings)

    override fun isModified(settings: CodeStyleSettings) = importsPanel.isModified(settings.cangjieCustomSettings)

    override fun getPanel() = content

    override fun resetImpl(settings: CodeStyleSettings) {
        importsPanel.reset(settings.cangjieCustomSettings)
    }

    override fun getTabTitle() = ApplicationBundle.message("title.imports")
}

private class ImportSettingsPanel {
    private lateinit var cbImportNestedClasses: JCheckBox

    private val starImportLayoutPanel = CangJieStarImportLayoutPanel()
    private val importOrderLayoutPanel = CangJieImportOrderLayoutPanel()

    private val nameCountToUseStarImportSelector = NameCountToUseStarImportSelector(
        CangJieBundle.message("formatter.title.top.level.symbols"),
        CangJieCodeStyleSettings.DEFAULT_NAME_COUNT_TO_USE_STAR_IMPORT,
    )

    private val nameCountToUseStarImportForMembersSelector = NameCountToUseStarImportSelector(
        CangJieBundle.message("formatter.title.java.statics.and.enum.members"),
        CangJieCodeStyleSettings.DEFAULT_NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS,
    )

    val panel = panel {
        with(nameCountToUseStarImportSelector) {
            buildUi()
        }
        with(nameCountToUseStarImportForMembersSelector) {
            buildUi()
        }

        group(CangJieBundle.message("formatter.title.other")) {
            row {
                cbImportNestedClasses =
                    checkBox(CangJieBundle.message("formatter.checkbox.text.insert.imports.for.nested.classes"))
                        .component
            }
        }

        row {
            cell(starImportLayoutPanel).align(AlignX.FILL)
        }.bottomGap(BottomGap.MEDIUM)

        row {
            cell(importOrderLayoutPanel).align(AlignX.FILL)
        }
    }.apply {
        border = JBUI.Borders.empty(0, 10, 10, 10)
    }

    fun reset(settings: CangJieCodeStyleSettings) {
        nameCountToUseStarImportSelector.value = settings.NAME_COUNT_TO_USE_STAR_IMPORT
        nameCountToUseStarImportForMembersSelector.value = settings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS

        cbImportNestedClasses.isSelected = settings.IMPORT_NESTED_CLASSES

        starImportLayoutPanel.packageTable.copyFrom(settings.PACKAGES_TO_USE_STAR_IMPORTS)
        (starImportLayoutPanel.layoutTable.model as AbstractTableModel).fireTableDataChanged()
        if (starImportLayoutPanel.layoutTable.rowCount > 0) {
            starImportLayoutPanel.layoutTable.selectionModel.setSelectionInterval(0, 0)
        }

        importOrderLayoutPanel.packageTable.copyFrom(settings.PACKAGES_IMPORT_LAYOUT)
        (importOrderLayoutPanel.layoutTable.model as AbstractTableModel).fireTableDataChanged()
        if (importOrderLayoutPanel.layoutTable.rowCount > 0) {
            importOrderLayoutPanel.layoutTable.selectionModel.setSelectionInterval(0, 0)
        }

        importOrderLayoutPanel.recomputeAliasesCheckbox()
    }

    fun apply(settings: CangJieCodeStyleSettings) {
        settings.NAME_COUNT_TO_USE_STAR_IMPORT = nameCountToUseStarImportSelector.value
        settings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS = nameCountToUseStarImportForMembersSelector.value
        settings.IMPORT_NESTED_CLASSES = cbImportNestedClasses.isSelected
        settings.PACKAGES_TO_USE_STAR_IMPORTS.copyFrom(getCopyWithoutEmptyPackages(starImportLayoutPanel.packageTable))
        settings.PACKAGES_IMPORT_LAYOUT.copyFrom(importOrderLayoutPanel.packageTable)
    }

    fun isModified(settings: CangJieCodeStyleSettings): Boolean {
        return with(settings) {
            var isModified = false
            isModified = isModified || nameCountToUseStarImportSelector.value != NAME_COUNT_TO_USE_STAR_IMPORT
            isModified =
                isModified || nameCountToUseStarImportForMembersSelector.value != NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS
            isModified = isModified || isModified(cbImportNestedClasses, IMPORT_NESTED_CLASSES)
            isModified = isModified ||
                    isModified(
                        getCopyWithoutEmptyPackages(starImportLayoutPanel.packageTable),
                        PACKAGES_TO_USE_STAR_IMPORTS
                    )

            isModified = isModified || isModified(importOrderLayoutPanel.packageTable, PACKAGES_IMPORT_LAYOUT)

            isModified
        }
    }

    companion object {
        private fun isModified(checkBox: JCheckBox, value: Boolean): Boolean {
            return checkBox.isSelected != value
        }

        private fun isModified(list: CangJiePackageEntryTable, table: CangJiePackageEntryTable): Boolean {
            if (list.entryCount != table.entryCount) {
                return true
            }

            for (i in 0 until list.entryCount) {
                val entry1 = list.getEntryAt(i)
                val entry2 = table.getEntryAt(i)
                if (entry1 != entry2) {
                    return true
                }
            }

            return false
        }

        private fun getCopyWithoutEmptyPackages(table: CangJiePackageEntryTable): CangJiePackageEntryTable {
            try {
                val copy = table.clone()
                copy.removeEmptyPackages()
                return copy
            } catch (ignored: CloneNotSupportedException) {
                throw IllegalStateException("Clone should be supported")
            }
        }
    }

    class NameCountToUseStarImportSelector(
        private val title: @NlsContexts.BorderTitle String,
        private val default: Int
    ) {
        private lateinit var rbUseSingleImports: JRadioButton
        private lateinit var rbUseStarImports: JRadioButton
        private lateinit var rbUseStarImportsIfAtLeast: JRadioButton
        private lateinit var starImportLimitField: JBIntSpinner

        fun Panel.buildUi() {
            buttonsGroup(title) {
                row {
                    rbUseSingleImports =
                        radioButton(CangJieBundle.message("formatter.button.text.use.single.name.import"))
                            .component
                }
                row {
                    rbUseStarImports = radioButton(CangJieBundle.message("formatter.button.text.use.import.with"))
                        .component
                }
                row {
                    rbUseStarImportsIfAtLeast =
                        radioButton(CangJieBundle.message("formatter.button.text.use.import.with.match.at.least"))
                            .gap(RightGap.SMALL)
                            .component
                    starImportLimitField = spinner(MIN_VALUE..MAX_VALUE)
                        .applyToComponent { number = default }
                        .gap(RightGap.SMALL)
                        .enabledIf(rbUseStarImportsIfAtLeast.selected)
                        .component
                    label(CangJieBundle.message("formatter.text.names.used"))
                }
            }
        }

        var value: Int
            get() {
                return when {
                    rbUseSingleImports.isSelected -> Int.MAX_VALUE
                    rbUseStarImports.isSelected -> 1
                    else -> starImportLimitField.number
                }
            }
            set(value) {
                when {
                    value > MAX_VALUE -> rbUseSingleImports.isSelected = true

                    value < MIN_VALUE -> rbUseStarImports.isSelected = true

                    else -> {
                        rbUseStarImportsIfAtLeast.isSelected = true
                        starImportLimitField.number = value
                    }
                }
            }

        companion object {
            private const val MIN_VALUE = 2
            private const val MAX_VALUE = 100
        }
    }
}
